﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using JigLibX.Collision;
using JigLibX.Physics;
using JigLibX.Geometry;
using JigLibX.Math;

namespace DARE
{
    public abstract class APhysicObject : ARenderable
    {

    #region identifier

        /// <summary>
        /// Specify the collision type for raycast.
        /// UNDEFINED is the default parameter
        /// NONE will not collide
        /// GROUND means that you can walk on it
        /// FADE is for walls and all objects that have to be rendered transparent when a ray intersect it
        /// CLICKABLE is for all objects that have an action on it, like open a door
        /// TRIGGER will call a method when a node is over the object
        /// </summary>
        public enum ECollisionType
        {
            UNDEFINED = 1, 
            NONE = 2, 
            GROUND = 4, 
            FADE = 8,
            HIGHLIGHT = 16,
            CLICKABLE = 32, 
            TRIGGER = 64
        }

    #endregion

    #region fields

        protected ECollisionType m_collisionType;
        protected Body m_body;
        protected CollisionSkin m_collisionSkin;
        protected Vector3 m_scale;
        protected CBasicModel m_basicModel;

    #endregion

    #region properties

        public ECollisionType CollisionType
        {
            get { return m_collisionType; }
            set { m_collisionType = value; }
        }

        public string CollisionTypeString
        {
            get
            {
                switch (m_collisionType)
                {
                    case ECollisionType.UNDEFINED: return "UNDEFINED";
                    case ECollisionType.NONE: return "NONE";
                    case ECollisionType.GROUND: return "GROUND";
                    case ECollisionType.FADE: return "FADE";
                    case ECollisionType.CLICKABLE: return "CLICKABLE";
                    case ECollisionType.TRIGGER: return "TRIGGER";
                    default: break;
                }
                return null;
            }
        }

        public Body Body
        {
            get { return m_body; }
        }

        public CollisionSkin Skin
        {
            get { return m_collisionSkin; }
        }

        public CBasicModel BasicModel
        {
            get { return m_basicModel; }
        }

    #endregion
        
    #region ctor

        public APhysicObject()
        {
            Initialize();
        }

        private void Initialize()
        {
            m_collisionType = ECollisionType.UNDEFINED;
            m_body = null;
            m_collisionSkin = null;
            m_scale = Vector3.One;
            m_basicModel = null;
        }

        public virtual APhysicObject Clone()
        {
            return this;
        }

        protected void CopyPropertiesTo(APhysicObject otherPhysicObject)
        {
            otherPhysicObject.BasicModel.Color = m_basicModel.Color;
            otherPhysicObject.CollisionType = m_collisionType;
            otherPhysicObject.BasicModel.Show = m_basicModel.Show;
            otherPhysicObject.BasicModel.FillMode = m_basicModel.FillMode;
            otherPhysicObject.BasicModel.CullMode = m_basicModel.CullMode;
        }

    #endregion

    #region run

        public override void Update(GameTime gameTime)
        {
            if ((m_body == null) || (m_collisionSkin == null) || (m_node == null))
                return;
            m_node.SetPhysicsTransform(m_body.Position, m_body.Orientation);
            Draw(gameTime);
        }

        public override void Draw(GameTime gameTime)
        {
            if (m_basicModel != null)
                m_basicModel.Draw(gameTime);
        }

    #endregion

    #region method

        public Vector3 SetMass(float mass)
        {
            float junk;
            Vector3 com;
            Matrix it, itCom;

            PrimitiveProperties primitivesProperties = new PrimitiveProperties(
                PrimitiveProperties.MassDistributionEnum.Solid, 
                PrimitiveProperties.MassTypeEnum.Density, 
                mass);
            m_collisionSkin.GetMassProperties(primitivesProperties, out junk, out com, out it, out itCom);
            m_body.BodyInertia = itCom;
            m_body.Mass = junk;
            return com;
        }

    #endregion

    }
}
